#include <iostream>   
#include <unistd.h>     
#include <pthread.h>    
#include "BlockQueue.hpp"  // 包含“自定义阻塞队列类头文件” ---> 线程安全的生产者-消费者队列
#include "Task.hpp"        // 包含“Task任务类头文件” ---> 结构化任务，支持两数相加逻辑


// /*------------------------------------------------------------【任务类型：类对象】------------------------------------------------------------*/

// /*------------------------------生产者线程入口函数 ---> 创建Task任务并放入阻塞队列------------------------------*/
// void *productor(void *args) //参数args：指向BlockQueue<Task>类型的阻塞队列指针（用于存放任务）
// {
//     //1.定义任务输入参数
//     int x = 1;  // 任务输入参数1（初始值1，每次生产后递增）
//     int y = 1;  // 任务输入参数2（初始值1，每次生产后递增）
    
//     //2.将void*类型参数转换为阻塞队列指针（与消费者共享同一个队列）
//     BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);

//     //3.生产者循环：持续生产任务
//     while (true)  
//     {
//         // sleep(1);  // 生产者每1秒生产一个任务；当前无休眠，快速生产任务
        
//         //1.打印生产任务的信息：告知用户当前生产的任务（两数相加的表达式）
//         std::cout << "生产了一个任务: " << x << "+" << y << "=?" << std::endl;
        
//         //2.创建Task任务对象：传入当前x和y作为计算参数
//         Task t(x, y);
 

//         /*3.将任务放入阻塞队列
//         *     1. 若队列已满（默认容量5），线程会阻塞等待，直到队列有空闲空间
//         *     2. 队列有空间时，将任务加入队尾（线程安全，内部已通过互斥锁同步）
//         */
//         bq->Push(t);  

//         //4.更新参数 ---> 下一个任务的输入参数递增（避免重复任务）
//         x++, y++;  
//     }
// }



// /*------------------------------消费者线程入口函数 ---> 从阻塞队列中获取任务并执行------------------------------*/
// void *consumer(void *args) //参数args：指向BlockQueue<Task>类型的阻塞队列指针（用于获取任务）
// {
//     //1.将void*类型参数转换为阻塞队列指针（队列存储Task类型任务）
//     BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);

//     //2.消费者循环：持续消费任务
//     while (true)  
//     {
//         sleep(1);  // 消费者每1秒消费一个任务

//         /*1.从阻塞队列中取出任务
//         *     1. 若队列为空，线程会阻塞等待，直到有生产者放入任务
//         *     2. 队列有任务时，取出队首任务并返回（线程安全，无需额外加锁）
//         */
//         Task t = bq->Pop();

//         //2.执行任务 ---> 调用Task类的Execute方法，计算两数之和（_x + _y）
//         t.Execute();

//         //3.打印任务执行结果 ---> 输出任务的输入参数和计算结果
//         std::cout << "消费了一个任务: " << t.X() << "+" << t.Y() << "=" << t.Result() << std::endl;
//     }
// }



/*------------------------------------------------------------【任务类型：函数对象】------------------------------------------------------------*/

/*------------------------------生产者线程入口函数 ---> 创建 task_t 类型任务并放入阻塞队列------------------------------*/
void *productor(void *args) //参数 args：指向 BlockQueue<task_t> 类型的阻塞队列指针（与消费者共享的任务缓冲区）
{
    //1.将 void* 类型的通用参数转换为具体的阻塞队列指针
    BlockQueue<task_t> *bq = static_cast<BlockQueue<task_t> *>(args);

    //2.生产者循环：持续生产任务
    while (true) 
    {
        sleep(1);  // 生产者者每1秒钟生产一个任务

        //2.1：日志打印 ---> 告知用户当前已生产一个任务
        std::cout << "生产了一个任务: " << std::endl;

        //2.2：生产任务 ---> 将 Download 函数封装为 task_t 类型，放入阻塞队列
        bq->Push(Download);
        /* 核心细节：
        *     1. Download 函数符合 task_t 类型签名（无参、返回值 void），可直接被 std::function 封装
        *     2. 调用 bq->Push 入队：若队列已满（默认容量5），生产者线程会阻塞等待，直到队列有空闲空间
        *     3. 入队操作是线程安全的，与消费者的 Pop 操作不会产生竞态条件
        */
    }
}


/*------------------------------消费者线程入口函数 ---> 从阻塞队列中获取并执行 task_t 类型的任务（无参无返回值）------------------------------*/
void *consumer(void *args) //参数 args：指向 BlockQueue<task_t> 类型的阻塞队列指针（生产者和消费者共享的任务缓冲区）
{
    //1.将 void* 类型的通用参数转换为具体的阻塞队列指针（队列存储 task_t 类型任务）
    BlockQueue<task_t> *bq = static_cast<BlockQueue<task_t> *>(args);

    //2.消费者循环：持续消费任务
    while (true)
    {
        //1.消费任务 ---> 从阻塞队列中取出一个 task_t 类型任务
        task_t t = bq->Pop();
        /* 核心特性：
        *     1. 若队列为空，消费者线程会阻塞等待，直到生产者放入任务
        *     2. 队列有任务时，原子性取出队首任务（阻塞队列内部已通过互斥锁保证线程安全）
        *     3. 取出的任务 t 是队列中任务的拷贝（或移动，取决于队列实现），此时任务已脱离队列控制
        */


        //2.处理任务 ---> 调用 task_t 类型的任务（本质是调用 std::function 封装的可调用对象）
        t();
        /* 关键说明：
        *     1. 任务执行时，已在当前消费者线程的上下文中，不再属于阻塞队列
        *     2. 队列仅负责任务的存储和传递，任务的执行逻辑由其自身定义（如 Download 函数的下载逻辑）
        *     3. 即使任务执行耗时，也不会影响队列的其他操作（生产者仍可入队，其他消费者仍可取队）
        */
    }
}



/*----------------------------------------主函数----------------------------------------*/
int main()
{
    /* 核心思路：阻塞队列可作为"任务队列"，实现生产者-消费者模型的任务分发
    *     1. 阻塞队列可直接存储基础数据类型（如int），也可以用于存储任务
    *     2. 生产者创建任务并放入队列，消费者从队列取任务并执行
    *     3. 阻塞队列自动处理"队列空/满"的阻塞逻辑，无需手动管理线程同步
    */

    /*---------------------------------------【单生产者&消费者模型】---------------------------------------*/

    /*----------------------------第一步：创建阻塞队列对象----------------------------*/
    /*=================【任务类型：类对象】=================*/
    //1.创建阻塞队列对象（存储Task类型任务，默认容量5）
    //BlockQueue<Task> *bq = new BlockQueue<Task>();


    /*=================【任务类型：函数对象】=================*/
    //1.创建阻塞队列对象（存储task_t类型任务，默认容量5）
    BlockQueue<task_t> *bq = new BlockQueue<task_t>();

    /*----------------------------第二步：定义并创建线程----------------------------*/
    //2.定义线程ID变量
    pthread_t p, c;

    //3.创建生产者线程 ---> 执行productor函数，传入阻塞队列指针作为参数
    pthread_create(&p, nullptr, productor, bq);
    //4.创建消费者线程 ---> 执行consumer函数，传入阻塞队列指针作为参数
    pthread_create(&c, nullptr, consumer, bq);


    /*----------------------------第二步：等待回收线程----------------------------*/
    //5.等待生产者&消费者线程执行完毕
    pthread_join(p, nullptr);
    pthread_join(c, nullptr);


    // /*---------------------------------------【多生产者&消费者模型】---------------------------------------*/
    // //1.创建阻塞队列对象（存储task_t类型任务，默认容量5）
    // BlockQueue<task_t> *bq = new BlockQueue<task_t>();

    // //2.构建生产者和消费者线程
    // pthread_t p[3], c[2];

    // pthread_create(p, nullptr, productor, bq);
    // pthread_create(p+1, nullptr, productor, bq);
    // pthread_create(p+2, nullptr, productor, bq);
    // pthread_create(c, nullptr, consumer, bq);
    // pthread_create(c+1, nullptr, consumer, bq);


    // //3.等待回收生产者和消费者线程
    // pthread_join(p[0], nullptr);
    // pthread_join(p[1], nullptr);
    // pthread_join(p[2], nullptr);
    // pthread_join(c[0], nullptr);
    // pthread_join(c[1], nullptr);

    return 0;
}